﻿using System.Collections.Concurrent;
using RpcHelper;
using RpcModel;
using RpcModel.RemoteLock;
using RpcSync.Service.Interface;

namespace RpcSync.Service.RemoteLock
{
    [RpcClient.Attr.ClassLifetimeAttr(RpcClient.Attr.ClassLifetimeType.单例)]
    internal class SyncLockService : ISyncLockService
    {
        private Timer _ClearLockTimer;
        private readonly ConcurrentDictionary<string, LockController> _LockList = new ConcurrentDictionary<string, LockController>();
        private IRemoteLockConfig _Config;
        public SyncLockService(IRemoteLockConfig config)
        {
            this._Config = config;
            this._ClearLockTimer = new Timer(new TimerCallback(_ClearLock), null, 1000, 1000);
        }

        private void _ClearLock(object state)
        {
            if (_LockList.Count == 0)
            {
                return;
            }
            string[] keys = _LockList.Keys.ToArray();
            keys.ForEach(a =>
            {
                if (_LockList.TryGetValue(a, out LockController syncLock))
                {
                    if (syncLock.CheckLock())
                    {
                        _LockList.TryRemove(a, out syncLock);
                    }
                }
            });
        }


        private LockController _ApplyLock(string lockId)
        {
            if (!_LockList.TryGetValue(lockId, out LockController syncLock))
            {
                return _LockList.GetOrAdd(lockId, new LockController(lockId, this._Config));
            }
            return syncLock;
        }

        public ApplyLockRes GetLockStatus(GetLockStatus obj)
        {
            if (!_LockList.TryGetValue(obj.LockId, out LockController syncLock))
            {
                throw new ErrorException("lock.not.find");
            }
            return syncLock.GetLockStatus(obj);
        }

        public ApplyLockRes ApplyLock(ApplyLock apply, long serverId)
        {
            LockController obj = _ApplyLock(apply.LockId);
            return obj.ApplyLock(apply, serverId);
        }
        public void ReleaseLock(ReleaseLock obj, long serverId)
        {
            if (!_LockList.TryGetValue(obj.LockId, out LockController syncLock))
            {
                throw new ErrorException("lock.not.find");
            }
            syncLock.ReleaseLock(obj, serverId);
        }
    }
}
